#pragma once

#include <iostream>
#include <string>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

// 在udp socket编程中，需要经常进行网络地址和主机地址之间转化
class InetAddr
{
public:
    InetAddr(const sockaddr_in &addr)  
        :_addr(addr)
    {
        // 网络转主机
        //_ip = inet_ntoa(addr.sin_addr); // 网络ip转化为点分十进制ip
        // inet_ntoa接口，它的返回值是char*，那么它的空间在哪呢？其实inet_ntoa内部有一个全局的缓冲区，该缓冲区是唯一的
        // 如果多次调用inet_ntoa就会导致后面的覆盖掉了前面的ip地址
        // 所以我们使用inet_ntop来替换inet_ntoa
        //const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
        char ipbuffer[64];
        _ip = inet_ntop(AF_INET, &_addr.sin_addr, ipbuffer, sizeof(_addr));
        _port = ntohs(addr.sin_port);
    }

    InetAddr(const std::string &ip, uint16_t port)
        : _ip(ip),
          _port(port)
    {
        // 主机转网络
        memset(&_addr, 0, sizeof(_addr));
        _addr.sin_family = AF_INET;
        _addr.sin_port = htons(_port);
        inet_pton(AF_INET, _ip.c_str(), &_addr.sin_addr);
        //int inet_pton(int af, const char *src, void *dst);
    }

    InetAddr(uint16_t port)
        : _port(port),
          _ip("")
    {
        // 适用于服务器绑定套接字信息
        memset(&_addr, 0, sizeof(_addr));
        _addr.sin_family = AF_INET;
        _addr.sin_port = htons(_port);
        _addr.sin_addr.s_addr = INADDR_ANY;
    }

    std::string Ip(){ return _ip; }
    uint16_t Port(){ return _port; }

    bool operator==(InetAddr &addr)
    {
        // 如果判断客户端是否相同->ip,prot
        // 也就意味着，一个主机可以启动多个客户端，因为客户端的端口号不同
        return _ip == addr._ip && _port == addr._port;

        // 如果一个主机只允许启动一个客户端
        // 那就只需要判断ip是否相同即可
        //return _ip == addr._ip;
    }

    std::string InetToString() { return _ip + ":" + std::to_string(_port); }

    const struct sockaddr_in& Getsockaddr() { return _addr; }

    ~InetAddr(){}
private:
    struct sockaddr_in _addr;
    std::string _ip;
    uint16_t _port;
};